1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package com.google.common.base;
18
19 import com.google.common.annotations.GwtCompatible;
20 import com.google.common.annotations.GwtIncompatible;
21 import com.google.common.base.Joiner.MapJoiner;
22 import com.google.common.collect.ImmutableMap;
23 import com.google.common.collect.ImmutableMultimap;
24 import com.google.common.collect.ImmutableSet;
25 import com.google.common.collect.Lists;
26 import com.google.common.collect.Maps;
27 import com.google.common.testing.NullPointerTester;
28
29 import junit.framework.AssertionFailedError;
30 import junit.framework.TestCase;
31
32 import java.io.IOException;
33 import java.util.Arrays;
34 import java.util.Iterator;
35 import java.util.Map;
36 import java.util.Set;
37
38
39
40
41
42
43 @GwtCompatible(emulated = true)
44 public class JoinerTest extends TestCase {
45 private static final Joiner J = Joiner.on("-");
46
47
48 private static final Iterable<Integer> ITERABLE_ = Arrays.<Integer>asList();
49 private static final Iterable<Integer> ITERABLE_1 = Arrays.asList(1);
50 private static final Iterable<Integer> ITERABLE_12 = Arrays.asList(1, 2);
51 private static final Iterable<Integer> ITERABLE_123 = Arrays.asList(1, 2, 3);
52 private static final Iterable<Integer> ITERABLE_NULL = Arrays.asList((Integer) null);
53 private static final Iterable<Integer> ITERABLE_NULL_NULL
54 = Arrays.asList((Integer) null, null);
55 private static final Iterable<Integer> ITERABLE_NULL_1 = Arrays.asList(null, 1);
56 private static final Iterable<Integer> ITERABLE_1_NULL = Arrays.asList(1, null);
57 private static final Iterable<Integer> ITERABLE_1_NULL_2 = Arrays.asList(1, null, 2);
58 private static final Iterable<Integer> ITERABLE_FOUR_NULLS
59 = Arrays.asList((Integer) null, null, null, null);
60
61 public void testNoSpecialNullBehavior() {
62 checkNoOutput(J, ITERABLE_);
63 checkResult(J, ITERABLE_1, "1");
64 checkResult(J, ITERABLE_12, "1-2");
65 checkResult(J, ITERABLE_123, "1-2-3");
66
67 try {
68 J.join(ITERABLE_NULL);
69 fail();
70 } catch (NullPointerException expected) {
71 }
72 try {
73 J.join(ITERABLE_1_NULL_2);
74 fail();
75 } catch (NullPointerException expected) {
76 }
77
78 try {
79 J.join(ITERABLE_NULL.iterator());
80 fail();
81 } catch (NullPointerException expected) {
82 }
83 try {
84 J.join(ITERABLE_1_NULL_2.iterator());
85 fail();
86 } catch (NullPointerException expected) {
87 }
88 }
89
90 public void testOnCharOverride() {
91 Joiner onChar = Joiner.on('-');
92 checkNoOutput(onChar, ITERABLE_);
93 checkResult(onChar, ITERABLE_1, "1");
94 checkResult(onChar, ITERABLE_12, "1-2");
95 checkResult(onChar, ITERABLE_123, "1-2-3");
96 }
97
98 public void testSkipNulls() {
99 Joiner skipNulls = J.skipNulls();
100 checkNoOutput(skipNulls, ITERABLE_);
101 checkNoOutput(skipNulls, ITERABLE_NULL);
102 checkNoOutput(skipNulls, ITERABLE_NULL_NULL);
103 checkNoOutput(skipNulls, ITERABLE_FOUR_NULLS);
104 checkResult(skipNulls, ITERABLE_1, "1");
105 checkResult(skipNulls, ITERABLE_12, "1-2");
106 checkResult(skipNulls, ITERABLE_123, "1-2-3");
107 checkResult(skipNulls, ITERABLE_NULL_1, "1");
108 checkResult(skipNulls, ITERABLE_1_NULL, "1");
109 checkResult(skipNulls, ITERABLE_1_NULL_2, "1-2");
110 }
111
112 public void testUseForNull() {
113 Joiner zeroForNull = J.useForNull("0");
114 checkNoOutput(zeroForNull, ITERABLE_);
115 checkResult(zeroForNull, ITERABLE_1, "1");
116 checkResult(zeroForNull, ITERABLE_12, "1-2");
117 checkResult(zeroForNull, ITERABLE_123, "1-2-3");
118 checkResult(zeroForNull, ITERABLE_NULL, "0");
119 checkResult(zeroForNull, ITERABLE_NULL_NULL, "0-0");
120 checkResult(zeroForNull, ITERABLE_NULL_1, "0-1");
121 checkResult(zeroForNull, ITERABLE_1_NULL, "1-0");
122 checkResult(zeroForNull, ITERABLE_1_NULL_2, "1-0-2");
123 checkResult(zeroForNull, ITERABLE_FOUR_NULLS, "0-0-0-0");
124 }
125
126 private static void checkNoOutput(Joiner joiner, Iterable<Integer> set) {
127 assertEquals("", joiner.join(set));
128 assertEquals("", joiner.join(set.iterator()));
129
130 Object[] array = Lists.newArrayList(set).toArray(new Integer[0]);
131 assertEquals("", joiner.join(array));
132
133 StringBuilder sb1FromIterable = new StringBuilder();
134 assertSame(sb1FromIterable, joiner.appendTo(sb1FromIterable, set));
135 assertEquals(0, sb1FromIterable.length());
136
137 StringBuilder sb1FromIterator = new StringBuilder();
138 assertSame(sb1FromIterator, joiner.appendTo(sb1FromIterator, set));
139 assertEquals(0, sb1FromIterator.length());
140
141 StringBuilder sb2 = new StringBuilder();
142 assertSame(sb2, joiner.appendTo(sb2, array));
143 assertEquals(0, sb2.length());
144
145 try {
146 joiner.appendTo(NASTY_APPENDABLE, set);
147 } catch (IOException e) {
148 throw new AssertionError(e);
149 }
150
151 try {
152 joiner.appendTo(NASTY_APPENDABLE, set.iterator());
153 } catch (IOException e) {
154 throw new AssertionError(e);
155 }
156
157 try {
158 joiner.appendTo(NASTY_APPENDABLE, array);
159 } catch (IOException e) {
160 throw new AssertionError(e);
161 }
162 }
163
164 private static final Appendable NASTY_APPENDABLE = new Appendable() {
165 @Override
166 public Appendable append(CharSequence csq) throws IOException {
167 throw new IOException();
168 }
169 @Override
170 public Appendable append(CharSequence csq, int start, int end) throws IOException {
171 throw new IOException();
172 }
173 @Override
174 public Appendable append(char c) throws IOException {
175 throw new IOException();
176 }
177 };
178
179 private static void checkResult(Joiner joiner, Iterable<Integer> parts, String expected) {
180 assertEquals(expected, joiner.join(parts));
181 assertEquals(expected, joiner.join(parts.iterator()));
182
183 StringBuilder sb1FromIterable = new StringBuilder().append('x');
184 joiner.appendTo(sb1FromIterable, parts);
185 assertEquals("x" + expected, sb1FromIterable.toString());
186
187 StringBuilder sb1FromIterator = new StringBuilder().append('x');
188 joiner.appendTo(sb1FromIterator, parts.iterator());
189 assertEquals("x" + expected, sb1FromIterator.toString());
190
191 Integer[] partsArray = Lists.newArrayList(parts).toArray(new Integer[0]);
192 assertEquals(expected, joiner.join(partsArray));
193
194 StringBuilder sb2 = new StringBuilder().append('x');
195 joiner.appendTo(sb2, partsArray);
196 assertEquals("x" + expected, sb2.toString());
197
198 int num = partsArray.length - 2;
199 if (num >= 0) {
200 Object[] rest = new Integer[num];
201 for (int i = 0; i < num; i++) {
202 rest[i] = partsArray[i + 2];
203 }
204
205 assertEquals(expected, joiner.join(partsArray[0], partsArray[1], rest));
206
207 StringBuilder sb3 = new StringBuilder().append('x');
208 joiner.appendTo(sb3, partsArray[0], partsArray[1], rest);
209 assertEquals("x" + expected, sb3.toString());
210 }
211 }
212
213 public void test_useForNull_skipNulls() {
214 Joiner j = Joiner.on("x").useForNull("y");
215 try {
216 j = j.skipNulls();
217 fail();
218 } catch (UnsupportedOperationException expected) {
219 }
220 }
221
222 public void test_skipNulls_useForNull() {
223 Joiner j = Joiner.on("x").skipNulls();
224 try {
225 j = j.useForNull("y");
226 fail();
227 } catch (UnsupportedOperationException expected) {
228 }
229 }
230
231 public void test_useForNull_twice() {
232 Joiner j = Joiner.on("x").useForNull("y");
233 try {
234 j = j.useForNull("y");
235 fail();
236 } catch (UnsupportedOperationException expected) {
237 }
238 }
239
240 public void testMap() {
241 MapJoiner j = Joiner.on(";").withKeyValueSeparator(":");
242 assertEquals("", j.join(ImmutableMap.of()));
243 assertEquals(":", j.join(ImmutableMap.of("", "")));
244
245 Map<String, String> mapWithNulls = Maps.newLinkedHashMap();
246 mapWithNulls.put("a", null);
247 mapWithNulls.put(null, "b");
248
249 try {
250 j.join(mapWithNulls);
251 fail();
252 } catch (NullPointerException expected) {
253 }
254
255 assertEquals("a:00;00:b", j.useForNull("00").join(mapWithNulls));
256
257 StringBuilder sb = new StringBuilder();
258 j.appendTo(sb, ImmutableMap.of(1, 2, 3, 4, 5, 6));
259 assertEquals("1:2;3:4;5:6", sb.toString());
260 }
261
262 public void testEntries() {
263 MapJoiner j = Joiner.on(";").withKeyValueSeparator(":");
264 assertEquals("", j.join(ImmutableMultimap.of().entries()));
265 assertEquals("", j.join(ImmutableMultimap.of().entries().iterator()));
266 assertEquals(":", j.join(ImmutableMultimap.of("", "").entries()));
267 assertEquals(":", j.join(ImmutableMultimap.of("", "").entries().iterator()));
268 assertEquals("1:a;1:b", j.join(ImmutableMultimap.of("1", "a", "1", "b").entries()));
269 assertEquals("1:a;1:b", j.join(ImmutableMultimap.of("1", "a", "1", "b").entries().iterator()));
270
271 Map<String, String> mapWithNulls = Maps.newLinkedHashMap();
272 mapWithNulls.put("a", null);
273 mapWithNulls.put(null, "b");
274 Set<Map.Entry<String, String>> entriesWithNulls = mapWithNulls.entrySet();
275
276 try {
277 j.join(entriesWithNulls);
278 fail();
279 } catch (NullPointerException expected) {
280 }
281
282 try {
283 j.join(entriesWithNulls.iterator());
284 fail();
285 } catch (NullPointerException expected) {
286 }
287
288 assertEquals("a:00;00:b", j.useForNull("00").join(entriesWithNulls));
289 assertEquals("a:00;00:b", j.useForNull("00").join(entriesWithNulls.iterator()));
290
291 StringBuilder sb1 = new StringBuilder();
292 j.appendTo(sb1, ImmutableMultimap.of(1, 2, 3, 4, 5, 6, 1, 3, 5, 10).entries());
293 assertEquals("1:2;1:3;3:4;5:6;5:10", sb1.toString());
294
295 StringBuilder sb2 = new StringBuilder();
296 j.appendTo(sb2, ImmutableMultimap.of(1, 2, 3, 4, 5, 6, 1, 3, 5, 10).entries().iterator());
297 assertEquals("1:2;1:3;3:4;5:6;5:10", sb2.toString());
298 }
299
300 @SuppressWarnings("ReturnValueIgnored")
301 public void test_skipNulls_onMap() {
302 Joiner j = Joiner.on(",").skipNulls();
303 try {
304 j.withKeyValueSeparator("/");
305 fail();
306 } catch (UnsupportedOperationException expected) {
307 }
308 }
309
310 private static class DontStringMeBro implements CharSequence {
311 @Override
312 public int length() {
313 return 3;
314 }
315 @Override
316 public char charAt(int index) {
317 return "foo".charAt(index);
318 }
319 @Override
320 public CharSequence subSequence(int start, int end) {
321 return "foo".subSequence(start, end);
322 }
323 @Override public String toString() {
324 throw new AssertionFailedError("shouldn't be invoked");
325 }
326 }
327
328
329 private static class IterableIterator implements Iterable<Integer>, Iterator<Integer> {
330 private static final ImmutableSet<Integer> INTEGERS = ImmutableSet.of(1, 2, 3, 4);
331 private final Iterator<Integer> iterator;
332 public IterableIterator() {
333 this.iterator = iterator();
334 }
335 @Override public Iterator<Integer> iterator() {
336 return INTEGERS.iterator();
337 }
338 @Override public boolean hasNext() {
339 return iterator.hasNext();
340 }
341 @Override public Integer next() {
342 return iterator.next();
343 }
344 @Override public void remove() {
345 iterator.remove();
346 }
347 }
348
349 @GwtIncompatible("StringBuilder.append in GWT invokes Object.toString(), unlike the JRE version.")
350 public void testDontConvertCharSequenceToString() {
351 assertEquals("foo,foo", Joiner.on(",").join(
352 new DontStringMeBro(), new DontStringMeBro()));
353 assertEquals("foo,bar,foo", Joiner.on(",").useForNull("bar").join(
354 new DontStringMeBro(), null, new DontStringMeBro()));
355 }
356
357 @GwtIncompatible("NullPointerTester")
358 public void testNullPointers() {
359 NullPointerTester tester = new NullPointerTester();
360 tester.testAllPublicStaticMethods(Joiner.class);
361 tester.testInstanceMethods(Joiner.on(","), NullPointerTester.Visibility.PACKAGE);
362 tester.testInstanceMethods(Joiner.on(",").skipNulls(), NullPointerTester.Visibility.PACKAGE);
363 tester.testInstanceMethods(
364 Joiner.on(",").useForNull("x"), NullPointerTester.Visibility.PACKAGE);
365 tester.testInstanceMethods(
366 Joiner.on(",").withKeyValueSeparator("="), NullPointerTester.Visibility.PACKAGE);
367 }
368 }